package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextTool;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/4
 * @description
 **/
public class LocatingLoadingElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {
    private static final String DEFAULT_BACKGROUND_COLOR = "#5d97ff";
    private static final String DEFAULT_UPPER_COMPASS_COLOR = "#fbc547";
    private static final String DEFAULT_LOWER_COMPASS_COLOR = "#ff614d";
    private Paint mPaint = new Paint();

    private Paint bottomOvalPaint;

    private String backgroundColor;

    private String upperCompassColor;

    private String lowerCompassColor;

    private int waterWidth = 100;

    private float fraction = 0f;

    private float rippleFraction = 0f;

    //水波纹以外的值动画
    private AnimatorValue animatorValue;
    //水波纹的值动画
    private AnimatorValue rippleAnimatorValue;

    private int duration = 1000;

    private int red = 153;

    private int green = 193;

    private int blue = 255;

    private float topPadding = 0f;
    private final float valueZeroPointTwo = 0.2f;

    private LocatingLoadingElement(IComponentCallback iComponentCallback) {
        this.callback = iComponentCallback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        animatorValue = new AnimatorValue();
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setDuration(duration);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            fraction = (float) Math.sin(2 * Math.PI * v);
            callback.reflushComponent();
        });

        rippleAnimatorValue = new AnimatorValue();
        rippleAnimatorValue.setLoopedCount(Animator.INFINITE);
        rippleAnimatorValue.setDuration(duration / 2);
        rippleAnimatorValue.setCurveType(Animator.CurveType.CUBIC_BEZIER_DECELERATION);
        rippleAnimatorValue.setValueUpdateListener((animatorValue, v) -> {
            if (v < valueZeroPointTwo) {
                rippleFraction = 0.2f;
            } else {
                rippleFraction = v;
            }
        });
        list.add(animatorValue);
        list.add(rippleAnimatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController<AnimatorValue> initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        bottomOvalPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);

        bottomOvalPaint.setStyle(Paint.Style.STROKE_STYLE);
        bottomOvalPaint.setStrokeWidth(7f);
        bottomOvalPaint.setAntiAlias(true);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        topPadding = (getHeight() - 1.7f * waterWidth) / 2f;
        drawRippleAndWaterDrop(canvas);
        drawInnerCircle(canvas);
        drawCompass(canvas);
    }

    //绘制指南针
    private void drawCompass(Canvas canvas) {
        canvas.save();
        canvas.rotate(15 * fraction, getWidth() / 2f, waterWidth * 0.5f + topPadding);
        Path upperPath = new Path();
        upperPath.moveTo(getWidth() / 2f - waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        upperPath.lineTo(getWidth() / 2f + waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        upperPath.lineTo(getWidth() / 2f, waterWidth * 0.25f + topPadding);
        upperPath.close();
        mPaint.setColor(new Color(Color.getIntColor(upperCompassColor)));
        canvas.drawPath(upperPath, mPaint);
        Path lowerPath = new Path();
        lowerPath.moveTo(getWidth() / 2f - waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        lowerPath.lineTo(getWidth() / 2f + waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        lowerPath.lineTo(getWidth() / 2f, waterWidth * 0.75f + topPadding);
        lowerPath.close();
        mPaint.setColor(new Color(Color.getIntColor(lowerCompassColor)));
        canvas.drawPath(lowerPath, mPaint);
        canvas.restore();
    }

    //绘制内部的两个圆
    private void drawInnerCircle(Canvas canvas) {
        int width = (int) getWidth();
        mPaint.setColor(new Color(Color.getIntColor("#8fbaff")));
        canvas.drawCircle(width / 2f, waterWidth * 0.5f + topPadding, waterWidth * 0.3f + waterWidth * 0.05f * fraction, mPaint);
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(width / 2f, waterWidth * 0.5f + topPadding, waterWidth * 0.3f, mPaint);
    }


    //绘制底部波纹与水滴
    private void drawRippleAndWaterDrop(Canvas canvas) {
        int width = (int) getWidth();
        float bottomX = width / 2f;
        float bottomY = waterWidth * 1.3f + topPadding;
        //绘制底部椭圆
        int alpha;
        if (Float.valueOf(rippleFraction).equals(valueZeroPointTwo)) {
            alpha = 0;
        } else {
            alpha = (int) (255 * (1 - rippleFraction));
        }
        Color ovalColor = new Color(Color.argb(alpha, red, green, blue));
        bottomOvalPaint.setColor(ovalColor);
        canvas.drawOval(new RectFloat(width / 2f - waterWidth * rippleFraction / 0.8f, bottomY - waterWidth * rippleFraction / 2.5f, width / 2f + waterWidth * rippleFraction / 0.8f, bottomY + waterWidth * rippleFraction / 2.5f), bottomOvalPaint);

        //绘制水滴上半部分
        mPaint.setColor(new Color(Color.getIntColor(backgroundColor)));
        canvas.drawArc(new RectFloat((width - waterWidth) / 2f, topPadding, (width + waterWidth) / 2f, waterWidth * 1.2f + topPadding), new Arc(0, -180, false), mPaint);
        //绘制水滴下半部分
        Path path = new Path();
        path.moveTo((width - waterWidth) / 2f, waterWidth * 0.6f + topPadding);
        path.quadTo(width / 2f - waterWidth / 2.6f, 19 / 20f * waterWidth + topPadding, bottomX, bottomY);
        path.quadTo(width / 2f + waterWidth / 2.6f, 19 / 20f * waterWidth + topPadding, (width + waterWidth) / 2f, waterWidth * 0.6f + topPadding);
        path.close();
        canvas.drawPath(path, mPaint);
    }
    private void apply(LocatingLoadingBuilder builder) {
        this.duration = builder.duration > 0 ? builder.duration : 1000;
        this.backgroundColor = !TextTool.isNullOrEmpty(builder.backgroundColor) ? builder.backgroundColor : DEFAULT_BACKGROUND_COLOR;
        this.upperCompassColor = !TextTool.isNullOrEmpty(builder.upperCompassColor) ? builder.upperCompassColor : DEFAULT_UPPER_COMPASS_COLOR;
        this.lowerCompassColor = !TextTool.isNullOrEmpty(builder.lowerCompassColor) ? builder.lowerCompassColor : DEFAULT_LOWER_COMPASS_COLOR;
        this.waterWidth = builder.waterWidth > 0 ? builder.waterWidth : 100;
        this.fraction = builder.fraction;
        this.rippleFraction = builder.rippleFraction;
    }

    public static class LocatingLoadingBuilder {
        private IComponentCallback iComponentCallback;
        private int duration;
        private String backgroundColor;
        private String upperCompassColor;
        private String lowerCompassColor;
        private int waterWidth;
        private float fraction = 0f;
        private float rippleFraction = 0f;

        public LocatingLoadingBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public LocatingLoadingBuilder setDuration(int duration) {
            this.duration = duration;
            return this;
        }

        public LocatingLoadingBuilder setBackgroundColor(String backgroundColor) {
            this.backgroundColor = backgroundColor;
            return this;
        }

        public LocatingLoadingBuilder setUpperCompassColor(String upperCompassColor) {
            this.upperCompassColor = upperCompassColor;
            return this;
        }

        public LocatingLoadingBuilder setLowerCompassColor(String lowerCompassColor) {
            this.lowerCompassColor = lowerCompassColor;
            return this;
        }

        public LocatingLoadingBuilder setWaterWidth(int waterWidth) {
            this.waterWidth = waterWidth;
            return this;
        }

        public LocatingLoadingBuilder setFraction(float fraction) {
            this.fraction = fraction;
            return this;
        }

        public LocatingLoadingBuilder setRippleFraction(float rippleFraction) {
            this.rippleFraction = rippleFraction;
            return this;
        }

        public LocatingLoadingElement build() {
            LocatingLoadingElement locatingLoadingElement = new LocatingLoadingElement(iComponentCallback);
            locatingLoadingElement.apply(this);
            return locatingLoadingElement;
        }
    }
}
